# -*- coding:utf-8 -*-

from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.dao.agent_client_dao import AgentClientDao
from module_admin.entity.do.client_do import AgentClient
from module_admin.entity.vo.agent_client_vo import (
    AgentClientModel,
    AgentClientQueryModel,
    AgentClientCreateModel,
    AgentClientUpdateModel,
    AgentClientCommandModel
)
from utils.page_util import PageResponseModel
from utils.log_util import logger
from typing import List, Optional, Dict
from datetime import datetime
import uuid


class AgentClientService:
    """Agent客户端业务逻辑层"""
    
    @classmethod
    async def get_client_list(
        cls,
        db: AsyncSession,
        query_params: AgentClientQueryModel,
        page_num: int = 1,
        page_size: int = 10,
        current_user_id: int = None,
        is_admin: bool = True
    ) -> PageResponseModel:
        """获取客户端列表（包含服务器主机名，支持权限过滤）"""
        clients_with_host, total = await AgentClientDao.get_client_list(
            db, query_params, page_num, page_size, current_user_id, is_admin
        )
        
        # 处理结果：clients_with_host 是 (client, server_host_name) 元组列表
        client_list = []
        for client, server_host_name in clients_with_host:
            client_dict = AgentClientModel.model_validate(client).model_dump()
            # 添加服务器主机名
            client_dict['server_host_name'] = server_host_name
            
            # 添加分配的用户名（用于前端显示）
            # ⚠️ 重要：管理员需要看到"分配给谁"，而不是"管理员管理"
            if client.assigned_user_id:
                assigned_user_name = await AgentClientDao.get_assigned_user_name(db, client.assigned_user_id)
                if assigned_user_name:
                    # 如果查询到用户名，直接使用
                    client_dict['assigned_user_name'] = assigned_user_name
                else:
                    # 如果查询结果为空，说明用户ID不存在或被删除，显示用户ID以便管理员查看
                    # 格式：已分配（用户ID: 1）
                    client_dict['assigned_user_name'] = f"已分配（用户ID: {client.assigned_user_id}）"
            else:
                # 只有assigned_user_id为None时，才显示"管理员管理"
                client_dict['assigned_user_name'] = None
            
            # 日志：记录IP和匹配的主机名
            if not server_host_name:
                logger.info(f"Agent客户端 {client.client_id} (IP: {client.ip_address}) 未匹配到服务器主机名")
            else:
                logger.info(f"Agent客户端 {client.client_id} (IP: {client.ip_address}) 匹配到主机名: {server_host_name}")
            
            client_list.append(client_dict)
        
        # 计算是否有下一页
        has_next = (page_num * page_size) < total
        
        return PageResponseModel(
            rows=client_list,
            total=total,
            pageNum=page_num,
            pageSize=page_size,
            hasNext=has_next
        )
    
    @classmethod
    async def get_client_detail(cls, db: AsyncSession, client_id: int) -> Optional[AgentClientModel]:
        """获取客户端详情"""
        client = await AgentClientDao.get_client_by_id(db, client_id)
        if client:
            return AgentClientModel.model_validate(client)
        return None
    
    @classmethod
    async def create_client(
        cls,
        db: AsyncSession,
        create_data: AgentClientCreateModel,
        create_by: int,
        dept_id: int
    ) -> AgentClientModel:
        """创建客户端（手动添加）"""
        # 生成唯一的client_id
        client_id = str(uuid.uuid4())
        
        client = AgentClient(
            client_name=create_data.client_name,
            client_id=client_id,
            client_type=create_data.client_type,
            remark=create_data.remark,
            online_status='offline',
            work_status='idle',
            browser_status='stopped',
            login_status='not_logged_in',
            status='0',
            create_by=create_by,
            dept_id=dept_id
        )
        
        created_client = await AgentClientDao.create_client(db, client)
        return AgentClientModel.model_validate(created_client)
    
    @classmethod
    async def update_client(
        cls,
        db: AsyncSession,
        client_id: int,
        update_data: AgentClientUpdateModel
    ):
        """更新客户端信息"""
        update_dict = update_data.model_dump(exclude_unset=True)
        if update_dict:
            await AgentClientDao.update_client(db, client_id, update_dict)
    
    @classmethod
    async def delete_client(cls, db: AsyncSession, client_id: int):
        """删除客户端"""
        await AgentClientDao.delete_client(db, client_id)
    
    @classmethod
    async def register_or_update_client(
        cls,
        db: AsyncSession,
        client_id: str,
        ip_address: str,
        port: int,
        create_by: int = 1,
        dept_id: int = 1
    ) -> AgentClient:
        """注册或更新客户端（TCP连接时调用）"""
        # 查找是否已存在
        client = await AgentClientDao.get_client_by_client_id(db, client_id)
        
        if client:
            # 更新连接信息
            update_data = {
                'ip_address': ip_address,
                'port': port,
                'connected_at': datetime.now(),
                'last_heartbeat': datetime.now(),
                'online_status': 'online'
            }
            await AgentClientDao.update_client_by_client_id(db, client_id, update_data)
            # 刷新
            await db.refresh(client)
        else:
            # 创建新客户端
            client = AgentClient(
                client_name=f'Client-{client_id[:8]}',
                client_id=client_id,
                ip_address=ip_address,
                port=port,
                client_type='search',
                online_status='online',
                work_status='idle',
                browser_status='stopped',
                login_status='not_logged_in',
                connected_at=datetime.now(),
                last_heartbeat=datetime.now(),
                status='0',
                create_by=create_by,
                dept_id=dept_id
            )
            client = await AgentClientDao.create_client(db, client)
        
        return client
    
    @classmethod
    async def update_client_status(
        cls,
        db: AsyncSession,
        client_id: str,
        status_data: dict
    ):
        """更新客户端状态（接收状态上报）"""
        await AgentClientDao.update_client_status(db, client_id, status_data)
    
    @classmethod
    async def mark_offline(cls, db: AsyncSession, client_id: str):
        """标记客户端离线"""
        update_data = {'online_status': 'offline'}
        await AgentClientDao.update_client_by_client_id(db, client_id, update_data)
    
    @classmethod
    async def get_client_by_client_id(cls, db: AsyncSession, client_id: str):
        """根据client_id获取客户端"""
        client = await AgentClientDao.get_client_by_client_id(db, client_id)
        return client
    
    @classmethod
    async def get_online_clients(cls, db: AsyncSession) -> List[AgentClientModel]:
        """获取所有在线客户端"""
        clients = await AgentClientDao.get_online_clients(db)
        return [AgentClientModel.model_validate(client) for client in clients]
    
    @classmethod
    async def get_available_search_clients(
        cls, 
        db: AsyncSession, 
        ignore_online_status: bool = False,
        user_id: Optional[int] = None  # ✅ 新增：用户ID（用于过滤）
    ) -> List[AgentClientModel]:
        """获取可用的搜索客户端（不要求已登录）
        
        Args:
            db: 数据库会话
            ignore_online_status: 是否忽略 online_status 过滤（默认False）
                                  当为True时，即使数据库状态是offline，只要client_type='search'就返回
                                  用于搜索调度器，因为调度器会使用TCP连接状态来验证真正的在线状态
        """
        # ✅ 搜索客户端不一定需要登录，只要在线即可
        # ✅ 如果 ignore_online_status=True，则从数据库获取所有 search 类型的客户端（不管 online_status）
        if ignore_online_status:
            # 直接查询，不过滤 online_status
            from sqlalchemy import select, desc
            
            query = select(AgentClient).where(
                AgentClient.del_flag == '0',
                AgentClient.client_type == 'search',
                AgentClient.status == '0'
            ).order_by(desc(AgentClient.last_heartbeat))
            result = await db.execute(query)
            clients = result.scalars().all()
            
        else:
            # ✅ 使用模块级别的 AgentClientDao 获取在线搜索客户端
            clients = await AgentClientDao.get_clients_by_type(db, 'search', require_login=False)
        
        
        # ✅ 严格验证：确保没有order类型的客户端（双重检查）
        order_clients = [c for c in clients if c.client_type and c.client_type.lower() == 'order']
        if order_clients:
            logger.error(f"❌ 严重错误：get_available_search_clients 返回了 {len(order_clients)} 个下单客户端！这不应该发生。")
            logger.error(f"下单客户端详情: {[(c.client_id, c.client_type) for c in order_clients]}")
            # 过滤掉order类型的客户端（包括大小写变体）
            clients = [c for c in clients if not (c.client_type and c.client_type.lower() == 'order')]
            logger.warning(f"已过滤掉order类型的客户端，剩余 {len(clients)} 个搜索客户端")
        
        # ✅ 最终验证：确保所有客户端都是search类型
        valid_clients = [c for c in clients if c.client_type and c.client_type.lower() == 'search']
        if len(valid_clients) != len(clients):
            logger.warning(f"⚠️ 发现 {len(clients) - len(valid_clients)} 个非search类型的客户端，已过滤")
            clients = valid_clients
        
        # ✅ 如果指定了user_id，只返回分配给该用户的搜索客户端
        if user_id is not None:
            filtered_clients = []
            for client in clients:
                # ✅ 简化：直接比较 assigned_user_id（1对1分配）
                if client.assigned_user_id == user_id:
                    filtered_clients.append(client)
                # 如果没有assigned_user_id，检查create_by（兼容旧数据）
                elif not client.assigned_user_id and client.create_by == user_id:
                    filtered_clients.append(client)
            clients = filtered_clients
        
        return [AgentClientModel.model_validate(client) for client in clients]
    
    @classmethod
    async def get_available_order_clients(
        cls, 
        db: AsyncSession, 
        allow_search_accounts: bool = False,
        user_id: Optional[int] = None
    ) -> List[AgentClientModel]:
        """
        获取可用的下单客户端（支持按user_id过滤）
        
        Args:
            allow_search_accounts: 是否允许使用搜索账号下单（临时方案，用于测试）
            user_id: 用户ID，如果提供则只返回分配给该用户的下单类型agent
        
        Returns:
            可用的下单客户端列表
        """
        # 优先获取下单类型的客户端（下单客户端必须已登录）
        order_clients = await AgentClientDao.get_clients_by_type(db, 'order', require_login=True)
        clients = [AgentClientModel.model_validate(client) for client in order_clients]
        
        # ✅ 如果指定了user_id，只返回分配给该用户的agent
        if user_id is not None:
            filtered_clients = []
            for client in clients:
                # ✅ 简化：直接比较 assigned_user_id（1对1分配）
                if client.assigned_user_id == user_id:
                    filtered_clients.append(client)
                # 如果没有assigned_user_id，检查create_by（兼容旧数据）
                elif not client.assigned_user_id and client.create_by == user_id:
                    filtered_clients.append(client)
            clients = filtered_clients
            logger.debug(f"✅ 按user_id={user_id}过滤下单客户端: {len(clients)}个")
        
        # ✅ 如果允许使用搜索账号，且没有下单账号，则添加搜索账号（下单需要已登录）
        # ✅ 但需要过滤掉被封禁的账号
        if allow_search_accounts and len(clients) == 0:
            search_clients = await AgentClientDao.get_clients_by_type(db, 'search', require_login=True)
            search_models = [
                AgentClientModel.model_validate(client) 
                for client in search_clients 
                if (client.work_status or 'idle') != 'banned'  # ✅ 排除被封禁的搜索账号
                and (client.work_status or 'idle') != 'error'  # ✅ 排除异常状态的搜索账号
            ]
            
            # ✅ 如果指定了user_id，也需要过滤搜索账号
            if user_id is not None:
                filtered_search = []
                for client in search_models:
                    # ✅ 简化：直接比较 assigned_user_id（1对1分配）
                    if client.assigned_user_id == user_id:
                        filtered_search.append(client)
                    # 如果没有assigned_user_id，检查create_by（兼容旧数据）
                    elif not client.assigned_user_id and client.create_by == user_id:
                        filtered_search.append(client)
                search_models = filtered_search
            
            clients.extend(search_models)
            if search_models:
                logger.info(f"使用搜索账号下单（临时方案）：找到 {len(search_models)} 个搜索账号")
        
        return clients
    
    @classmethod
    async def assign_clients_to_users(
        cls,
        db: AsyncSession,
        client_ids: List[int],
        user_id: Optional[int] = None
    ):
        """分配agent给用户（1对1分配，管理员专用）
        
        Args:
            db: 数据库会话
            client_ids: 要分配的agent ID列表
            user_id: 分配的用户ID（单个用户），None表示取消分配（回归管理员管理）
        """
        await AgentClientDao.assign_clients_to_users(db, client_ids, user_id)
        logger.info(f"Agent分配成功：{len(client_ids)}个agent分配给用户{user_id}")
    
    @classmethod
    async def check_agent_access_permission(
        cls,
        db: AsyncSession,
        client_id: str,
        current_user_id: int,
        is_admin: bool
    ) -> bool:
        """检查用户是否有权访问/操作此agent
        
        Args:
            db: 数据库会话
            client_id: Agent的client_id
            current_user_id: 当前用户ID
            is_admin: 是否是管理员
            
        Returns:
            True: 有权访问
            False: 无权访问
        """
        # 管理员有权访问所有agent
        if is_admin:
            return True
        
        # 非管理员：检查assigned_user_id（1对1分配）
        client = await cls.get_client_by_client_id(db, client_id)
        if not client:
            logger.warning(f"Agent {client_id} 不存在")
            return False
        
        # 未分配的agent只有管理员能访问
        if not client.assigned_user_id:
            logger.warning(f"Agent {client_id} 未分配，用户 {current_user_id} 无权访问")
            return False
        
        # ✅ 简化：直接比较 assigned_user_id（1对1分配）
        has_permission = client.assigned_user_id == current_user_id
        
        if not has_permission:
            logger.warning(f"用户 {current_user_id} 无权访问Agent {client_id}（分配给: {client.assigned_user_id}）")
        
        return has_permission

